package com.the_last.service;

import com.the_last.config.RabbitConfig;
import com.the_last.constant.ReservationConstant;
import com.the_last.mapper.TimeSlotMapper;
import com.the_last.pojo.po.Reservation;
import com.the_last.utils.TimeUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.UUID;

/**
 * 预约超时消息服务
 * 负责发送预约超时延迟消息到RabbitMQ
 * 
 * @author zhanghaifeng
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ReservationTimeoutMessageService {
    
    private final RabbitTemplate rabbitTemplate;
    private final TimeSlotMapper timeSlotMapper;
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    
    /**
     * 发送预约超时延迟消息
     * 根据预约的结束时间计算TTL，在预约结束后的缓冲期自动标记为超时
     * 
     * @param reservation 预约信息
     * @param maxTimeSlotId 预约中最大的时间段ID
     */
    public void sendReservationTimeoutMessage(Reservation reservation, Integer maxTimeSlotId) {
        String currentTime = LocalDateTime.now().format(FORMATTER);
        String messageId = UUID.randomUUID().toString();
        
        try {
            // 参数校验
            if (maxTimeSlotId == null) {
                log.warn("预约最大时间段ID为空，无法发送超时消息，预约ID: {}", reservation.getId());
                return;
            }
            
            // 1. 根据最大时间段ID获取结束时间
            String endTimeStr = timeSlotMapper.selectEndTimeById(maxTimeSlotId);
            
            if (endTimeStr == null) {
                log.warn("时间段不存在，无法发送超时消息，预约ID: {}, 时间段ID: {}", reservation.getId(), maxTimeSlotId);
                return;
            }
            
            // 2. 计算预约结束的具体时间
            Date reservationDate = reservation.getReservationDate();
            String reservationDateStr = TimeUtil.dateFormat.format(reservationDate);
            
            // 将预约日期和结束时间合并成完整的结束时间戳
            Date reservationEndDateTime = TimeUtil.dateTimeFormat.parse(reservationDateStr + " " + endTimeStr);
            
            // 3. 计算TTL：预约结束时间 + 缓冲期 - 当前时间
            long currentTimeMillis = System.currentTimeMillis();
            long reservationEndTimeMillis = reservationEndDateTime.getTime();
            long ttlMillis = reservationEndTimeMillis - currentTimeMillis;
            
            log.info("[{}] 发送预约超时延迟消息", currentTime);
            log.info("预约ID: {}", reservation.getId());
            log.info("消息ID: {}", messageId);
            log.info("最大时间段ID: {}, 结束时间: {}", maxTimeSlotId, endTimeStr);
            log.info("预约结束时间: {}", TimeUtil.dateTimeFormat.format(reservationEndDateTime));
            log.info("超时触发时间: {}", TimeUtil.dateTimeFormat.format(new Date(reservationEndTimeMillis)));
            log.info("TTL时间: {} 毫秒 ({} 分钟)", ttlMillis, ttlMillis / 60000);
            
            // 4. 发送带有动态TTL的消息到延时队列
            rabbitTemplate.convertAndSend(
                RabbitConfig.RESERVATION_DELAY_EXCHANGE,
                RabbitConfig.RESERVATION_DELAY_QUEUE,
                reservation.getId().toString(),
                message -> {
                    // 设置消息级别的TTL
                    message.getMessageProperties().setExpiration(String.valueOf(ttlMillis));
                    message.getMessageProperties().setMessageId(messageId);
                    message.getMessageProperties().setTimestamp(new Date());
                    return message;
                }
            );
            
            log.info("预约超时延迟消息发送成功，预约ID: {}, 消息ID: {}", reservation.getId(), messageId);
            
        } catch (Exception e) {
            log.error("发送预约超时延迟消息失败，预约ID: {}", reservation.getId(), e);
            throw new RuntimeException("发送预约超时消息失败", e);
        }
    }
}